/**
 * 
 */
package valfazz.android.karfinder.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import valfazz.android.karfinder.R;
import valfazz.android.karfinder.database.DatabaseHelper;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.res.Resources;
import android.database.DatabaseUtils.InsertHelper;
import android.net.ConnectivityManager;
import android.os.AsyncTask;
import android.os.SystemClock;
import android.util.Log;
import android.widget.Toast;

/**
 * @author Val
 *
 */
public class SongUpdater {
	private int maxValue = 0;
	private Resources res;
	private JSONArray jsonArray;
	private DatabaseHelper dbHelper;
	private Context context;
	private final String updateURL = "http://cloud.classep.co.cc/api";
	
	public SongUpdater(Context context) {
		this.context = context;
		res = context.getResources();
		dbHelper = new DatabaseHelper(context);
	}
	
	public boolean isOnline() {
		try {
			Log.v(this.getClass().getName() + " Test", "Kiem tra ket noi");
			ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
			return cm.getActiveNetworkInfo().isConnectedOrConnecting();
		} catch (Exception e) {
			return false;
		}
	}
	
	public int getLastestOnlineVolume() {
		int result = -1;
		
		try {
			HttpURLConnection conn = (HttpURLConnection) new URL(updateURL + "/volume/lastest").openConnection();
			int fileSize = conn.getContentLength();
	       	ByteArrayOutputStream out = new ByteArrayOutputStream(fileSize);
	    	byte[] buffer = new byte[fileSize];
	    	InputStream stream = conn.getInputStream();
	    	
	       	while (stream.read(buffer) != -1);
	       	out.write(buffer, 0, fileSize);
	       	
	       	Log.v("out content", out.toString());
	       	
	       	JSONObject jsonObj = new JSONObject(out.toString());
	       	stream.close();
	       	conn.disconnect();
	       	result = jsonObj.getInt("lastestVolume");
		} catch (Exception e) {
			Log.e("Error", e.getMessage());
		}
		
		return result;
	}
	
	public void updateFromInternet() {
		if (isOnline() == true) {
			int onlineVolume = getLastestOnlineVolume();
			int offlineVolume = dbHelper.getLastestOfflineVolume();
			
			if (onlineVolume > offlineVolume) {
				(new AsyncDownloadTask(offlineVolume + 1)).execute();
			} else {
				Toast.makeText(context, R.string.song_updater_no_new_volume, Toast.LENGTH_SHORT).show();
			}
		} else {
			Toast.makeText(context, R.string.song_updater_network_error, Toast.LENGTH_SHORT).show();
			dbHelper.close();
		}
	}
	
	public void updateFromFile() {
		if (dbHelper.isEmptyDatabase()) {
			try {
				InputStream is = res.openRawResource(R.raw.songlist_ori_db1);
				jsonArray = new JSONArray(convertStreamToString(is));
				//Log.i("jsonArray size()", jsonArray.length() + "");
				is = res.openRawResource(R.raw.songlist_ori_db2);
				JSONArray temp = new JSONArray(convertStreamToString(is));
				for (int i = 0; i < temp.length(); ++i)
					jsonArray.put(temp.get(i));
				//Log.i("jsonArray size()", jsonArray.length() + "");
				is = res.openRawResource(R.raw.songlist_ori_db3);
				temp = new JSONArray(convertStreamToString(is));
				for (int i = 0; i < temp.length(); ++i)
					jsonArray.put(temp.get(i));
				is.close();
				maxValue = jsonArray.length();
			} catch (JSONException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			new AsyncDatabaseUpdater().execute();
		} else {
			this.dbHelper.close();
		}
	}
	
	public String convertStreamToString(InputStream in) {
		String jsonText = null;
		try {
			byte[] buffer = new byte[in.available()];
			while (in.read(buffer) != -1);
			jsonText = new String(buffer);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return jsonText;
	}
	
	class AsyncDownloadTask extends AsyncTask<Void, Integer, Void> {
		private HttpURLConnection conn;
    	private InputStream stream;
    	private ByteArrayOutputStream out;
    	private int fileSize;
    	private int downloaded;
    	private int status;
    	private int newVolume;
    	private int responseCode;
    	
    	private ProgressDialog downloadProgDialog;
    	
    	private final int MAX_BUFFER_SIZE = 1024;
    	private final int DOWNLOADING = 0;
    	private final int COMPLETED = 1;
		
		public AsyncDownloadTask(int newVolume) {
			this.newVolume = newVolume;
			status = DOWNLOADING;
			fileSize = downloaded = 0;
			downloadProgDialog = new ProgressDialog(context);
		}
		
		@Override
		protected void onPreExecute() {
			downloadProgDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
			downloadProgDialog.setMessage(res.getString(R.string.song_updater_downloading));
			downloadProgDialog.setCancelable(false);
			downloadProgDialog.show();
		}

		@Override
		protected Void doInBackground(Void... unused) {
			try {
				conn = (HttpURLConnection)new URL(updateURL + "/volume/" + newVolume).openConnection();
				responseCode = conn.getResponseCode();
				if (responseCode == HttpURLConnection.HTTP_OK) {
					fileSize = conn.getContentLength();
					out = new ByteArrayOutputStream(fileSize);
					conn.connect();
					
					Log.v("fileSize", fileSize + "");
					downloadProgDialog.setMax(fileSize);
					
					stream = conn.getInputStream();
					
					while (status == DOWNLOADING) {
						byte buffer[];
						
						if (fileSize - downloaded > MAX_BUFFER_SIZE) {
							buffer = new byte[MAX_BUFFER_SIZE];
						} else {
							buffer = new byte[fileSize - downloaded];
						}
						
						//Log.v("buffer size", buffer.length + "");
						
						int read = stream.read(buffer);
						
						//Log.i("read status", read + "");
						
						if (read == -1) {
							publishProgress(fileSize);
							status = COMPLETED;
							break;
						}
						
						out.write(buffer, 0, read);
						downloaded += read;
						publishProgress(downloaded);
					} // end of while
					
					stream.close();
					conn.disconnect();

					jsonArray = new JSONArray(out.toString());
					maxValue = jsonArray.length();
				}
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (JSONException e) {
				e.printStackTrace();
			}
			return null;
		}

		@Override
		protected void onProgressUpdate(Integer... values) {
			downloadProgDialog.setProgress(values[0]);
		}

		@Override
		protected void onPostExecute(Void result) {
			downloadProgDialog.dismiss();
			if (responseCode == HttpURLConnection.HTTP_OK) {
				new AsyncDatabaseUpdater().execute();
			} else {
				Toast.makeText(context, R.string.song_updater_no_new_volume, Toast.LENGTH_SHORT).show();
				dbHelper.close();
			}
		}
	}
	
	private class AsyncDatabaseUpdater extends AsyncTask<Void, Integer, Void> {
		private ProgressDialog updateProgDialog;
		private int updateValue = 500;// maxValue/13;
		
		public AsyncDatabaseUpdater() {
			updateProgDialog = new ProgressDialog(context);
		}
		
		@Override
		protected void onPreExecute() {
			updateProgDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
			updateProgDialog.setMessage(res.getString(R.string.song_updater_please_wait));
			updateProgDialog.setMax(maxValue);
			updateProgDialog.show();
		}

		@Override
		protected Void doInBackground(Void... unused) {
			InsertHelper ih = new InsertHelper(dbHelper.getDB(), "SONG");
			try {
				/* new version */
				int song_id = ih.getColumnIndex("SONG_ID");
				int song_title = ih.getColumnIndex("SONG_TITLE");
				int song_lyrics = ih.getColumnIndex("SONG_LYRICS");
				int song_composer = ih.getColumnIndex("SONG_COMPOSER");
				int song_language = ih.getColumnIndex("SONG_LANGUAGE");
				int song_genre = ih.getColumnIndex("SONG_GENRE");
				int song_volume = ih.getColumnIndex("SONG_VOLUME");
				int song_favorite = ih.getColumnIndex("SONG_IS_FAVORITE");
				int song_tenbaihat = ih.getColumnIndex("TEN_BAI_HAT");
				int song_loimodau = ih.getColumnIndex("LOI_MO_DAU");
				int song_tacgia = ih.getColumnIndex("TAC_GIA");
				String str;
				dbHelper.getDB().setLockingEnabled(false);
				dbHelper.getDB().beginTransaction();
				long startTime = SystemClock.currentThreadTimeMillis();
				long endTime;
				for (int i = 0; i < maxValue; ++i) {
					ih.prepareForInsert();
					JSONArray value = jsonArray.getJSONArray(i);
					
					ih.bind(song_id, value.getInt(0));
					ih.bind(song_title, value.getString(1));
					ih.bind(song_lyrics, value.getString(2));
					ih.bind(song_composer, value.getString(3));
					ih.bind(song_language, value.getString(4));
					ih.bind(song_genre, value.getString(5));
					ih.bind(song_volume, value.getInt(6));
					ih.bind(song_favorite, 0);
					ih.bind(song_tenbaihat, value.getString(7));
					
					str = value.getString(8);
					if (!str.equals(""))
						ih.bind(song_loimodau, str);
					
					str = value.getString(9);
					if (!str.equals(""))
						ih.bind(song_tacgia, str);
					
					ih.execute();

					endTime = SystemClock.currentThreadTimeMillis();
					if (endTime - startTime > updateValue) {
						publishProgress(i+1);
						startTime = SystemClock.currentThreadTimeMillis();
					}
				}
				dbHelper.getDB().setTransactionSuccessful();
				dbHelper.getDB().setLockingEnabled(true);
				
				
				/* old version
				for (int i = 0; i < maxValue; ++i) {
					dbHelper.insertSong(jsonArray.getJSONArray(i));
					if ((i+1)%(maxValue/10) == 0)
						publishProgress();
				}
				*/
			} catch (JSONException e) {
				e.printStackTrace();
			} finally {
				ih.close();
				dbHelper.getDB().endTransaction();
			}
			return null;
		}
		
		@Override
		protected void onProgressUpdate(Integer... update) {
			updateProgDialog.setProgress(update[0]);
		}
		
		@Override
		protected void onPostExecute(Void result) {
			updateProgDialog.dismiss();
			dbHelper.close();
		}
	}
}
